<template>
  <div :class="containerCss">
    <div key="begin" class="animation-begin" v-bind:class="containerCss" v-if="isAnimationCompleted" :style="afterStyle">
      <slot></slot>
    </div>
    <div key="end" class="animation-end" v-bind:class="containerCss" ref="end" v-else>
      <div class="animation-end-slot">
        <slot></slot>
      </div>
      <div v-for="(chunkStyle, index) in chunkStyles" :key="index" class="animation-end-chunk" :style="chunkStyle"></div>
    </div>
  </div>
</template>

<script>
    /* eslint-disable */

    const kMinSize = 30;
  const kMaxSize = 50;

  export default {
    name: "animate-roll",
    data () {
      return {
        afterStyle: '',
        isAnimationCompleted: false,
        chunkStyles: []
      }
    },
    props: {
      containerCss: String,
      beforeColor: String,
      afterColor: String,
      // 动画持续时间，单位是ms
      duration: Number,
      // 动画递增间隔，单位是ms
      incDuration: Number,
      // chunk 尺寸
      chunkSize: Number,
      // 根据每行个数取当前 Chunk 尺寸
      chunkSizePerRowCount: Number,
      // 根据每列个数取当前 Chunk 尺寸
      chunkSizePerColCount: Number,
      direction: 'left-top' | 'right-bottom' | 'left-bottom' | 'right-top',
      end: Function
    },

    methods: {
      getHeight() {
        return this.$refs.end.offsetHeight;
      },
      getWidth() {
        return this.$refs.end.offsetWidth;
      },
      calculateChunkStyles() {
        var vm = this;
        var beforeColor = this.beforeColor ? this.beforeColor : '#e34981';
        var afterColor = this.afterColor ? this.afterColor : '#e34981';
        var duration = this.duration ? this.duration : 300;
        var incDuration = this.incDuration ? this.incDuration : 40;
        var direction = this.direction ? this.direction : 'left-top';
        var width = this.getWidth();
        var height = this.getHeight();
        var size = kMinSize;
        if(this.chunkSizePerRowCount) {
          size = width / this.chunkSizePerRowCount;
        }
        else if(this.chunkSizePerColCount) {
          size = height / this.chunkSizePerColCount;
        }
        else {
          if (width < kMinSize || height < kMinSize) {
            size = width > height ? height : width;
          }
          else if (width >= kMaxSize && height >= kMaxSize) {
            size = kMaxSize;
          }
          else {
            size = width > height ? height : width;
          }
          if (this.chunkSize && this.chunkSize < size) {
            size = this.chunkSize;
          }
        }
        var rowCount = Math.ceil(width / size);
        var colCount = Math.ceil(height / size);
        var style = 'width: ' + size + "px; height: " + size + "px; ";
        var left = 0;
        var top = 0;
        var maxDelay = 0;

        switch(direction) {
          case 'left-top': {
            top = 0;
            for(var i = 0 ; i < colCount ; i ++) {
              var delay = i * incDuration;
              left = 0;
              for(var j = 0 ; j < rowCount ; j ++ ) {
                var rowDelay = delay + j * incDuration;
                if(rowDelay > maxDelay) {
                  maxDelay = rowDelay;
                }
                var chunkStyle = style + 'left: ' + left + 'px; top: ' + top + 'px; ' +
                  'animation: chunk ' + duration + 'ms linear ' + rowDelay + 'ms;' +
                  'animation-fill-mode: forwards;';
                this.chunkStyles.push(chunkStyle);
                left += size;
              }
              top += size;
            }
            break;
          }

          case 'right-top': {
            top = 0;
            for(var i = 0 ; i < colCount ; i ++) {
              var delay = i * incDuration;
              left = (rowCount - 1) * size;
              for(var j = rowCount - 1 ; j >= 0 ; j -- ) {
                var rowDelay = delay + (rowCount - 1 - j) * incDuration;
                if(rowDelay > maxDelay) {
                  maxDelay = rowDelay;
                }
                var chunkStyle = style + 'left: ' + left + 'px; top: ' + top + 'px; ' +
                  'animation: chunk ' + duration + 'ms linear ' + rowDelay + 'ms;' +
                  'animation-fill-mode: forwards;';
                this.chunkStyles.push(chunkStyle);
                left -= size;
              }
              top += size;
            }
            break;
          }

          case 'left-bottom': {
            top = (colCount - 1) * size;
            for(var i = 0 ; i < colCount ; i ++) {
              var delay = i * incDuration;
              left = 0;
              for(var j = 0 ; j < rowCount ; j ++ ) {
                var rowDelay = delay + j * incDuration;
                if(rowDelay > maxDelay) {
                  maxDelay = rowDelay;
                }
                var chunkStyle = style + 'left: ' + left + 'px; top: ' + top + 'px; ' +
                  'animation: chunk ' + duration + 'ms linear ' + rowDelay + 'ms;' +
                  'animation-fill-mode: forwards;';
                this.chunkStyles.push(chunkStyle);
                left += size;
              }
              top -= size;
            }
            break;
          }

          case 'right-bottom': {
            top = (colCount - 1) * size;
            for(var i = 0 ; i < colCount ; i ++) {
              var delay = i * incDuration;
              left = (rowCount - 1) * size;
              for(var j = rowCount - 1 ; j >= 0 ; j -- ) {
                var rowDelay = delay + (rowCount - 1 - j) * incDuration;
                if(rowDelay > maxDelay) {
                  maxDelay = rowDelay;
                }
                var chunkStyle = style + 'left: ' + left + 'px; top: ' + top + 'px; ' +
                  'animation: chunk ' + duration + 'ms linear ' + rowDelay + 'ms;' +
                  'animation-fill-mode: forwards;';
                this.chunkStyles.push(chunkStyle);
                left -= size;
              }
              top -= size;
            }
            break;
          }
        }

        this.afterStyle = 'background-color: ' + afterColor;
        this.$refs.end.innerHTML += '<style>@keyframes chunk {\n' +
          '    0% {\n' +
          '      background-color: '+ beforeColor +';\n' +
          '      transform: rotate3d(1, 0, 0, 90deg);\n' +
          '    }\n' +
          '    100% {\n' +
          '      background-color: ' + afterColor + ';\n' +
          '      transform: rotate3d(1, 0, 0, 0deg);\n' +
          '    }}</style>';

        return maxDelay + duration;
      }
    },

    mounted() {
      var vm = this;
      setTimeout(() => {
        vm.isAnimationCompleted = true;
        if(vm.end != null) {
          vm.end();
        }
      }, this.calculateChunkStyles());
    }
  }
</script>

<style scoped>
  .animation-begin {
    position: relative;
    opacity: 100%;
    overflow: hidden;
    display: inline-block;
  }

  .animation-end {
    position: relative;
    overflow: hidden;
    display: inline-block;
  }

  .animation-end-slot {
    opacity: 0;
    display: inline-block;
  }

  .animation-end-chunk {
    position: absolute;

  }
</style>
